Repository navigation
feat(pr-pipeline): cut the lane hold-path floor to the merge gate's own - #9541
Conversation
resolve-config no longer forces .github/** into merge.diff-check.denied-paths, and merge-holds.mjs drops its path-wide plugin.json and marketplace.json globs. Its floor is the forced paths plus babysit_risk.HIGH_FLOOR, and ci-status compares a changed manifest base against head as the gate's manifest review does (manifestChanges, kept equal to babysit_risk._manifest_changes by test_merge_holds_sync). enable-auto-merge already scores manifests through evidence --lane-reviews. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
PR body contract — issue linkage This PR body does not yet satisfy the issue-linkage contract:
Edit the body and this comment updates itself on the next run. |
Review fixes for the hold-path floor cut: - matchesHoldPath folds case, as glob_match and costHold do, so .github/codeowners or .github/actions/Resolve-Config/ holds. - The HIGH floor and HOLD_PATH_FLOOR hold .github/actions/check-kill-switch/**: check-trusted-trigger and resolve-config write their verdicts through its writeOutputs. A test walks both actions' imports and fails on any file the floor does not hold, and the floor test compares matched paths, case variants included, instead of glob strings. - Manifest contents decode as strict UTF-8 with the BOM kept, and an integer past int_max_str_digits holds, as the gate's json.loads refuses it. - A path hold and a manifest hold both reach the reason. - New manifest cases: hooks true to null and to false, a 20-digit integer, -0.0 to 0.0. - The workflows premise names what it covers: lanes App pushes only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-review reviewed Incremental review of 5fb7023..818f914 (adds
Not a finding, but worth a look: the changelog fragment I ran no tests or commands; everything above is from reading the diff and files. |
|
claude-security-review reviewed Incremental security review of 818f914 against 5fb7023: I found no security issues. The change adds
manifest: not applicable, because the incremental diff touches no critical-findings: 0 |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: owner direction 2026-10-24, lowest-friction hold floor
Summary
The lanes' native auto-merge path held more than the merge gate does. Two extra holds are cut here, down to the gate's own floor, which is the takeover set in
babysit_risk.HIGH_FLOOR(owner direction 2026-10-23):merge-holds.mjsHOLD_PATH_FLOORheld every**/.claude-plugin/plugin.jsonand.claude-plugin/marketplace.jsonpath-wide. Soenable-auto-mergenever armed a lane PR that touched a manifest, even for auserConfigdefault (the feat(source-control)!: ship the pr_open_state default as ready #9483 shape).resolveMergeforced.github/**intomerge.diff-check.denied-paths. That held every lane PR touching.github/scriptsor.github/actionsin report-outcome'sHold:line, inenable-auto-mergeand inci-status.What still holds a manifest:
enable-auto-merge. It already scored manifests through the gate's reader:evidence --lane-reviewsrunslane_risk_refusal, which reads both sides (with_contents) and scoresmanifest-review-requiredwith this repository'shigh-path-floor: true.ci-status. Its lanes App step had no such scoring. The glob was its only manifest check, and it is what caught a push after arming whose disarm failed. Somerge-holds.mjsgets a port of the gate's comparison (manifestChanges, the rule ofbabysit_risk._manifest_changes), with no blanket glob. Both sides are read at the base commit and the head and compared key by key.The classes held are the ones #9280 set:
_EXECUTABLE_KEYSvalue differing (hooks, mcpServers, lspServers, monitors), orexperimental.monitors;namechanged;A
userConfigdefault or a version bump merges.Fix
resolve.mjsresolveMergedrops.github/**and keeps the config path and the trusted-actor list.merge-holds.mjsFORCED_DENIED_PATHSmatches it (merge-authority.test.mjs).HOLD_PATH_FLOORis now the forced paths plus eachHIGH_FLOORglob, listed one by one. Before,.github/**was what covered.github/actions/resolve-config/**,.github/actions/check-trusted-trigger/**and.github/standards/trusted-actors/**. A sync test checks thatHOLD_PATH_FLOORcontainsbabysit_risk.HIGH_FLOOR.merge-holds.mjsaddsmanifestChangesandmanifestHold. The port keeps two Python behaviors:_no_duplicatesdoes;json.dumps(sort_keys=True)tells apart (1and1.0,falseand0).[filename, previous_filename, status]per file and exportsBASE_SHA. A line in the older format has no status, so a manifest on it holds. A module older than this one reads the extra entries as paths that match no hold path.enable-auto-mergefixture and the tests that stated the old floor are updated.workflows:request-lane-token/action.ymlchecks the broker's grant is exactly contents, pull-requests, issues and at most actions. That covers lanes App pushes only. Another identity with write access could still push a workflow change after auto-merge is armed.Review fixes at ready (security and code review of 4f4b0e2):
matchesHoldPathfolds case, asglob_matchandcostHolddo. Without it,.github/codeowners,.github/actions/Resolve-Config/…,.github/Standards/trusted-actors/…and.github/actions/Check-Trusted-Trigger/…went unheld once.github/**left.HIGH_FLOORandHOLD_PATH_FLOORadd.github/actions/check-kill-switch/**. check-trusted-trigger and resolve-config both import their output writer (writeOutputs) from it, and.github/**was what held it before.test_merge_holds_sync.pynow compares matched paths, case variants included, betweenpathHoldandglob_match. A new test walks the two floor actions' imports and fails on any file the floor does not hold.int_max_str_digitsholds, since the gate'sjson.loadsrefuses it. A path hold and a manifest hold both reach the reason.Verification
nice bash scripts/check-affected.sh --uncommitted: 12 passed, 4 skipped.node --testover.github/scripts/pr-merge/*.test.mjs: 271 pass, 0 fail.node --testover.github/actions/resolve-config/*.test.mjs: 680 pass, 0 fail.node --testover.github/scripts/work-resolve-issue/*.test.mjs: 257 pass, 0 fail.bash scripts/ci-lanes-pr-hold.test.sh: 128 pass, 0 fail.uv run --with pytest python -m pytest plugins/source-control/skills/babysit-prs/scripts/tests: 2738 passed.scripts/check-affected.sh --testspassed 14 of 14, run with PyYAML on PATH. Each new sync test fails with its fix reverted (seven case variants unheld, andcheck-kill-switch.mjsunheld).merge-holds.test.mjsholds every feat(source-control): merge MED lane PRs on review pass and cut the path floor to external effects #9280 class through ci-status's command line, and passes auserConfigdefault (feat(source-control)!: ship the pr_open_state default as ready #9483).test_merge_holds_sync.pychecks the JS comparison againstbabysit_risk._manifest_changesover 30 cases.test_babysit_lane_reviews.pychecks thatlane_risk_refusal, the native arm path, holds a hooks, mcpServers orexperimental.monitorschange and passes auserConfigdefault.enable-auto-merge.test.mjschecks thatdecide()arms on a null risk score and disarms on a manifest one.This PR changes
.github/actions/resolve-config/**, which is on the HIGH floor, so a person merges it.🤖 Generated with Claude Code